﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using LFSRecord2.Events;
using LFSRecord2.Model;
using LFSRecord2.Model.UserActions;
using LFSRecord2.View.TimelineStructures;
using LFSRecord2.ViewModel;
using IOPath = System.IO.Path;

namespace LFSRecord2.View
{
    /// <summary>
    /// Interaction logic for TimelineView.xaml
    /// </summary>
    public partial class TimelineView : UserControl
    {
        Rectangle _selectionRectangle;

        public static DependencyProperty ProjectLengthProperty = DependencyProperty.Register(
          "ProjectLength",
          typeof(double),
          typeof(TimelineView),
          new FrameworkPropertyMetadata(new PropertyChangedCallback(OnProjectLengthChanged))
        );
        public double ProjectLength
        {
            get { return (double)GetValue(ProjectLengthProperty); }
            set { SetValue(ProjectLengthProperty, value); }
        }
        private static void OnProjectLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((TimelineView)d).createRuler();
        }

        public static DependencyProperty ProjectFPSProperty = DependencyProperty.Register(
          "ProjectFPS",
          typeof(byte),
          typeof(TimelineView),
          new FrameworkPropertyMetadata(new PropertyChangedCallback(OnProjectFPSChanged))
        );
        public byte ProjectFPS
        {
            get { return (byte)GetValue(ProjectFPSProperty); }
            set { SetValue(ProjectFPSProperty, value); }
        }
        private static void OnProjectFPSChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((TimelineView)d).createRuler();
        }

        public static DependencyProperty CurrentFrameProperty = DependencyProperty.Register(
          "CurrentFrame",
          typeof(int),
          typeof(TimelineView),
          new FrameworkPropertyMetadata(new PropertyChangedCallback(OnCurrentFrameChanged))
        );
        public int CurrentFrame
        {
            get { return (int)GetValue(CurrentFrameProperty); }
            set { SetValue(CurrentFrameProperty, value); }
        }
        private static void OnCurrentFrameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((TimelineView)d).CurrentFrameChangedHandler();
        }

        public TimelineView()
        {
            InitializeComponent();
            _selectionRectangle = new Rectangle();
            _selectionRectangle.SetValue(Grid.RowProperty, 1);
            _selectionRectangle.IsHitTestVisible = false;
            _selectionRectangle.Stroke = new SolidColorBrush(Color.FromArgb(220, 255, 185, 157));
            _selectionRectangle.Fill = new SolidColorBrush(Color.FromArgb(80, 158, 128, 108));
            _selectionRectangle.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            _selectionRectangle.VerticalAlignment = System.Windows.VerticalAlignment.Top;
            _selectionRectangle.Width = 0;
            _selectionRectangle.Height = 0;
            TimelineOverlayCanvas.Children.Add(_selectionRectangle);
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            TimelineViewModel tvm = (TimelineViewModel)DataContext;

            // Setup some bindings
            Binding myBinding = new Binding("ProjectLength");
            myBinding.Mode = BindingMode.TwoWay;
            myBinding.Source = tvm;
            SetBinding(TimelineView.ProjectLengthProperty, myBinding);

            myBinding = new Binding("ProjectFPS");
            myBinding.Mode = BindingMode.TwoWay;
            myBinding.Source = tvm;
            SetBinding(TimelineView.ProjectFPSProperty, myBinding);

            myBinding = new Binding("CurrentFrame");
            myBinding.Mode = BindingMode.OneWay;
            myBinding.Source = tvm;
            SetBinding(TimelineView.CurrentFrameProperty, myBinding);

            // Create TimeIndicator
            DoubleValueEditControl TimeIndicator = createTimeIndicator();
            TimeIndicator.Height = 24;
            TimeIndicator.CanSlow = false;
            TimeIndicator.Margin = new Thickness(4, -4, 0, 0);
            TimelineTime.Children.Add(TimeIndicator);

            SetupContextMenu();
        }

        private DoubleValueEditControl createTimeIndicator()
        {
            Binding myBinding;

            DoubleValueEditControl dec = new DoubleValueEditControl();
            dec.DataContext = null;
            dec.DisplayType = ValueEditControlDisplayTypes.FrameTimestamp;
            dec.ValueName = "CurrentFrame";
            dec.FontSize = 16;
            dec.HorizontalAlignment = HorizontalAlignment.Left;
            dec.InputBox.VerticalAlignment = VerticalAlignment.Bottom;
            dec.InputBox.VerticalContentAlignment = VerticalAlignment.Bottom;
            dec.InputBox.Margin = new Thickness(-1, 0, 0, 0);
            dec.InputBox.Padding = new Thickness(-1, 0, 0, -1);
            dec.InputBox.Height = double.NaN;

            myBinding = new Binding("CurrentFrame");
            myBinding.Mode = BindingMode.TwoWay;
            myBinding.Source = (TimelineViewModel)DataContext;
            dec.SetBinding(DoubleValueEditControl.ValueProperty, myBinding);
            //dec.PropertyChanged += handleValueChange;

            dec.writeLabelValue();

            return dec;
        }

        private void createRuler()
        {
            //Debug.WriteLine("drawing ruler");
            // First check if CurrentFrame will be beyond project length
            if (CurrentFrame > ProjectLength * ProjectFPS)
                ((TimelineViewModel)DataContext).CurrentFrame = (int)(ProjectLength * ProjectFPS);

            TimelineRuler.Children.Clear();

            double width = Math.Ceiling((ProjectLength) * ProjectFPS);
            double height = 21.0d;

            TimelineRuler.Width = width;
            TimelineRuler.Height = height - 1;

            int a = 0;
            int s = 0;
            int sec = 0;
            int tWidth = 0;
            TextBlock t;
            Line l;
            while (a < width)
            {
                l = new Line();
                //l.SnapsToDevicePixels = true;
                l.Stroke = Brushes.White;
                l.X1 = l.X2 = a + 0.5;
                l.Y1 = height - 6;
                l.Y2 = height - 1;
                TimelineRuler.Children.Add(l);

                t = new TextBlock();
                sec = s % 60;
                if (sec > 0)
                    t.Text = sec + "s";
                else
                    t.Text = Math.Floor(s / 60.0f) + "m";

                tWidth = (sec < 10) ? 5 : 7;
                t.Margin = new Thickness(a - tWidth, 2, 0, 0);
                t.FontFamily = new FontFamily("Arial");
                t.FontSize = 9;
                t.Foreground = Brushes.White;
                TimelineRuler.Children.Add(t);

                a += ProjectFPS;
                s++;
            }
        }

        Point _startPoint;
        Thickness _origMargin;
        private void TimePointer_MouseDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            TimePointer.IsHitTestVisible = false;

            _origMargin = TimePointer.Margin;
            _startPoint = e.GetPosition(TimelineRuler);

            Application.Current.MainWindow.CaptureMouse();
            Application.Current.MainWindow.MouseLeftButtonUp += TimePointer_MouseLeftButtonUp;
            Application.Current.MainWindow.MouseMove += TimePointer_MouseMove;
        }

        private void TimelineRuler_MouseDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            TimePointer.IsHitTestVisible = false;

            Point mPos = e.GetPosition(TimelineRuler);
            if (mPos.X > (int)Math.Floor(ProjectLength * ProjectFPS))
                mPos.X = (int)Math.Floor(ProjectLength * ProjectFPS);
            ((TimelineViewModel)DataContext).CurrentFrame = (int)mPos.X;

            _origMargin = TimePointer.Margin;
            _startPoint = e.GetPosition(TimelineRuler);

            Application.Current.MainWindow.CaptureMouse();
            Application.Current.MainWindow.MouseLeftButtonUp += this.TimePointer_MouseLeftButtonUp;
            Application.Current.MainWindow.MouseMove += this.TimePointer_MouseMove;
        }

        private void TimePointer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            Application.Current.MainWindow.ReleaseMouseCapture();
            Application.Current.MainWindow.MouseLeftButtonUp -= this.TimePointer_MouseLeftButtonUp;
            Application.Current.MainWindow.MouseMove -= this.TimePointer_MouseMove;
            TimePointer.IsHitTestVisible = true;

            if (LfsRecordController.project.HasReplay())
            {
                ServicesFactory.EventService.GetEvent<FrameIndexChangedEvent>().Publish(
                    new FrameIndexChangedEventArgs()
                    {
                        Sender = this,
                        NewFrameIndex = CurrentFrame,
                        UpdateCurrentValues = true,
                        UpdateReplayPosition = true
                    });
            }
        }

        private void TimePointer_MouseMove(object sender, MouseEventArgs e)
        {
            e.Handled = true;
            Point curPoint = e.GetPosition(TimelineRuler);
            Point diff = new Point(_startPoint.X - curPoint.X, _startPoint.Y - curPoint.Y);

            double leftMargin = Math.Round(_origMargin.Left - diff.X) + 6;
            if (leftMargin < 0)
                leftMargin = 0;
            else if (leftMargin > (int)Math.Floor(ProjectLength * ProjectFPS))
                leftMargin = (int)Math.Floor(ProjectLength * ProjectFPS);

            ((TimelineViewModel)DataContext).CurrentFrame = (int)leftMargin;
        }

        public void CurrentFrameChangedHandler()
        {
            TimePointer.Margin = new Thickness(CurrentFrame - 6, 1, 0, 0);
        }

        int _selectionID = 0;
        private void KeyViewGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
            {
                LfsRecordController.project.DeselectAll();
            }

            // Sync IsSelectedBackup variables
            _selectionID = 1;
            LfsRecordController.project.SyncIsSelectedBackup();

            // Prepare for selection rectangle
            Application.Current.MainWindow.CaptureMouse();
            Application.Current.MainWindow.MouseLeftButtonUp += SelectRectangle_MouseLeftButtonUp;
            Application.Current.MainWindow.MouseMove += SelectRectangle_MouseMove;
            _startPoint = e.GetPosition(KeyViewStackPanel);
            this.IsHitTestVisible = false;

            // We need to trigger the redraw of both the keylanes and viewport
            //ServicesFactory.EventService.GetEvent<CameraPathChangedEvent>().Publish("euhm");
        }

        private void SelectRectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            Application.Current.MainWindow.ReleaseMouseCapture();
            Application.Current.MainWindow.MouseLeftButtonUp -= SelectRectangle_MouseLeftButtonUp;
            Application.Current.MainWindow.MouseMove -= SelectRectangle_MouseMove;
            this.IsHitTestVisible = true;
            _selectionRectangle.Visibility = Visibility.Hidden;
        }

        private void SelectRectangle_MouseMove(object sender, MouseEventArgs e)
        {
            e.Handled = true;
            Point curPoint = e.GetPosition(KeyViewStackPanel);
            Point diff = new Point(curPoint.X - _startPoint.X, curPoint.Y - _startPoint.Y);

            Point rectCoord = new Point(_startPoint.X, _startPoint.Y);

            if (diff.X < 0)
            {
                diff.X = -diff.X;
                rectCoord.X -= diff.X;
            }
            if (diff.Y < 0)
            {
                diff.Y = -diff.Y;
                rectCoord.Y -= diff.Y;
            }

            //Debug.WriteLine("Select coord : " + rectCoord.X + "," + rectCoord.Y + " - size : " + diff.X + "," + diff.Y);

            // Transform selection rectangle
            _selectionRectangle.Width = diff.X;
            _selectionRectangle.Height = diff.Y;
            _selectionRectangle.RenderTransform = new TranslateTransform(rectCoord.X, rectCoord.Y + KeyViewStackPanel.Margin.Top);
            _selectionRectangle.Visibility = Visibility.Visible;

            // Figure out which keyframes are selected
            KeyFrameHitTestResultList.Clear();
            VisualTreeHelper.HitTest(KeyViewStackPanel,
                new HitTestFilterCallback(KeyFrameHitTestFilter),
                new HitTestResultCallback(KeyFrameHitTestResult),
                new GeometryHitTestParameters(new RectangleGeometry(new Rect(new Point(rectCoord.X, rectCoord.Y), new Size(diff.X, diff.Y)))));

            // Process hit keyframes
            CustomKeyFrame kf;
            if (KeyFrameHitTestResultList.Count > 0)
            {
                foreach (DependencyObject o in KeyFrameHitTestResultList)
                {
                    kf = (CustomKeyFrame)((KeyImageControl)o).DataContext;
                    kf.SelectionID = _selectionID;

                    if (kf.IsSelectedBackup == kf.IsSelected)
                        kf.IsSelected = !kf.IsSelected;
                }
            }

            // Deselect keyframes that were previously selected, but not anymore
            LfsRecordController.project.ResetKeyFrameSelectionNotHit(_selectionID++);
        }

        private HitTestFilterBehavior KeyFrameHitTestFilter(DependencyObject o)
        {
            ItemsControl ic;

            if (o.GetType() == typeof(ItemsControl))
            {
                ic = (ItemsControl)o;
                if (ic.Name == "KeyLaneItems" && ic.Visibility != Visibility.Visible)
                    return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
                else
                    return HitTestFilterBehavior.Continue;
            }
            else
            {
                return HitTestFilterBehavior.Continue;
            }
        }

        private List<DependencyObject> KeyFrameHitTestResultList = new List<DependencyObject>();

        public HitTestResultBehavior KeyFrameHitTestResult(HitTestResult result)
        {
            if (result.VisualHit.GetType() == typeof(KeyImageControl))
                KeyFrameHitTestResultList.Add(result.VisualHit);
            return HitTestResultBehavior.Continue;
        }

        private void TimelineVerticalScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            double availableHeight = TimelineOverlayCanvas.ActualHeight;
            double objectHeight = KeyViewStackPanel.ActualHeight;
            double availableMoveAmount = objectHeight - availableHeight;

            if (availableMoveAmount <= 0)
            {
                KeyViewStackPanel.Margin = new Thickness(0, 0, 0, 0);
                InfoViewStackPanel.Margin = new Thickness(0, 0, 0, 0);
                return;
            }

            KeyViewStackPanel.Margin = new Thickness(0, Math.Round(-availableMoveAmount * e.NewValue), 0, 0);
            InfoViewStackPanel.Margin = new Thickness(0, Math.Round(-availableMoveAmount * e.NewValue), 0, 0);
        }

        private void VerticalScrollGrid_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            // Adjust scrolling
            double availableHeight = TimelineOverlayCanvas.ActualHeight;
            double targetActualHeight = KeyViewStackPanel.ActualHeight;
            double availableMoveAmount = targetActualHeight - availableHeight;

            //Debug.WriteLine("Scroll resize : " + availableHeight + " - " + targetActualHeight + " - " + availableMoveAmount + " - " + KeyViewStackPanel.Margin.Top);

            if (availableMoveAmount <= 0)
            {
                KeyViewStackPanel.Margin = new Thickness(0, 0, 0, 0);
                InfoViewStackPanel.Margin = new Thickness(0, 0, 0, 0);
                TimelineVerticalScrollBar.Value = 0;
                TimelineVerticalScrollBar.IsEnabled = false;
                TimelineVerticalScrollBar.Track.Thumb.Visibility = Visibility.Hidden;
                return;
            }
            TimelineVerticalScrollBar.IsEnabled = true;
            TimelineVerticalScrollBar.Track.Thumb.Visibility = Visibility.Visible;
            TimelineVerticalScrollBar.ViewportSize = (availableHeight / targetActualHeight) / (1 - (availableHeight / targetActualHeight));
            TimelineVerticalScrollBar.SmallChange = 18 / availableMoveAmount;
            TimelineVerticalScrollBar.LargeChange = 72 / availableMoveAmount;

            if (-KeyViewStackPanel.Margin.Top > availableMoveAmount)
            {
                KeyViewStackPanel.Margin = new Thickness(0, Math.Round(-availableMoveAmount), 0, 0);
                InfoViewStackPanel.Margin = new Thickness(0, Math.Round(-availableMoveAmount), 0, 0);
                TimelineVerticalScrollBar.Value = 1;
                return;
            }

            TimelineVerticalScrollBar.Value = -KeyViewStackPanel.Margin.Top / availableMoveAmount;
        }

        private void ScrollViewer_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            double newValue;

            if (e.Delta > 0)
            {
                if (TimelineVerticalScrollBar.Value > 0)
                {
                    newValue = TimelineVerticalScrollBar.Value - TimelineVerticalScrollBar.SmallChange;
                    if (newValue < 0)
                        newValue = 0;
                    TimelineVerticalScrollBar.Value = newValue;
                    TimelineVerticalScrollBar_Scroll(null, new ScrollEventArgs(ScrollEventType.SmallDecrement, newValue));
                }
            }
            else
            {
                if (TimelineVerticalScrollBar.Value < 1)
                {
                    newValue = TimelineVerticalScrollBar.Value + TimelineVerticalScrollBar.SmallChange;
                    if (newValue > 1)
                        newValue = 1;
                    TimelineVerticalScrollBar.Value = newValue;
                    TimelineVerticalScrollBar_Scroll(null, new ScrollEventArgs(ScrollEventType.SmallIncrement, newValue));
                }
            }

        }

        private void OutsideViewer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            if (!Keyboard.IsKeyDown(Key.LeftShift))
                LfsRecordController.project.DeselectAll();
        }

        public void SetupContextMenu()
        {
            // Create context menu
            MenuItem mi, mi2;
            ContextMenu cm = new ContextMenu();

            // Add layer
            mi = new MenuItem();
            mi.Name = "AddLayer";
            mi.Header = "Add Layer";

            mi2 = new MenuItem();
            mi2.Name = "LookCamera";
            mi2.Header = "Look Camera";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.LookCamera;
            mi.Items.Add(mi2);

            mi2 = new MenuItem();
            mi2.Name = "FreeCamera";
            mi2.Header = "Free Camera";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.FreeCamera;
            mi.Items.Add(mi2);

            mi2 = new MenuItem();
            mi2.Name = "NullLayer";
            mi2.Header = "Null";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.Null;
            mi.Items.Add(mi2);

            mi2 = new MenuItem();
            mi2.Name = "ReplayControl";
            mi2.Header = "Replay Control";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.ReplayControl;
            mi.Items.Add(mi2);

            mi2 = new MenuItem();
            mi2.Name = "ReplayData";
            mi2.Header = "Replay Data";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.ReplayData;
            mi.Items.Add(mi2);

            mi2 = new MenuItem();
            mi2.Name = "AudioLayer";
            mi2.Header = "Audio Track";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.Audio;
            mi.Items.Add(mi2);

            cm.Items.Add(mi);

            LayerInfoGrid.ContextMenu = cm;
        }

        // Add layer command
        RelayCommand _addLayerClickedCommand;
        public ICommand AddLayerClickedCommand
        {
            get
            {
                if (_addLayerClickedCommand == null)
                    _addLayerClickedCommand = new RelayCommand(param => AddLayer_ClickedCommandExecute(param), param => AddLayer_ClickedCommandCanExecute(param));
                return _addLayerClickedCommand;
            }
        }
        static void AddLayer_ClickedCommandExecute(object param)
        {
            CompLayerTypes layerType = (CompLayerTypes)param;
            CompLayerBase l = null;
            AudioLayer al = null;
            switch (layerType)
            {
                case CompLayerTypes.LookCamera:
                    l = LfsRecordController.project.AddLookCamera();
                    break;
                case CompLayerTypes.FreeCamera:
                    l = LfsRecordController.project.AddFreeCamera();
                    break;
                case CompLayerTypes.Null:
                    l = LfsRecordController.project.AddNull();
                    break;
                case CompLayerTypes.ReplayControl:
                    l = LfsRecordController.project.AddReplayControl();
                    break;
                case CompLayerTypes.ReplayData:
                    l = LfsRecordController.project.AddReplayData();
                    break;
                case CompLayerTypes.Audio:
                    al = LfsRecordController.project.AddAudio();
                    break;
            }

            if (l != null)
            {
                LfsRecordController.RecordUserAction(new UserActionAddLayer()
                {
                    LayerType = l.LayerType,
                    LayerIndex = l.LayerIndex,
                    LayerName = l.LayerName
                });
            }
            else if (al != null)
            {
                LfsRecordController.RecordUserAction(new UserActionAddLayer()
                {
                    LayerType = al.LayerType,
                    LayerIndex = al.LayerIndex,
                    LayerName = al.LayerName
                });
            }
            LfsRecordController.CreateUndoLevel();
        }
        static bool AddLayer_ClickedCommandCanExecute(object param)
        {
            if (param == null)
                return true;

            CompLayerTypes layerType = (CompLayerTypes)param;
            if (layerType == CompLayerTypes.ReplayControl)
            {
                return (LfsRecordController.project.NumLayersOfType(CompLayerTypes.ReplayControl) > 0) ? false : true;
            }
            return true;
        }

        private static bool TryGetReplayFileName(DataObject dataObject, out string replayFileName)
        {
            if (dataObject.ContainsFileDropList())
            {
                StringCollection dropList = dataObject.GetFileDropList();
                if (dropList.Count == 1)
                {
                    string replayExt = IOPath.GetExtension(dropList[0]);
                    if (replayExt == ".spr" || replayExt == ".mpr")
                    {
                        replayFileName = IOPath.GetFileName(dropList[0]);
                        return true;
                    }
                }
            }

            replayFileName = null;
            return false;
        }

        private void InfoViewStackPanel_DragOver(object sender, DragEventArgs e)
        {
            string temp;

            // Cancel drag if the file is not a LFS replay.
            e.Effects = TryGetReplayFileName((DataObject)e.Data, out temp) ? DragDropEffects.All : DragDropEffects.None;
            e.Handled = true;
        }

        private void InfoViewStackPanel_Drop(object sender, DragEventArgs e)
        {
            string replayFileName;
            if (TryGetReplayFileName((DataObject)e.Data, out replayFileName))
            {
                if (LfsRecordController.project.HasReplay())
                {
                    UpdateReplayControlLayer(replayFileName);
                }
                else
                {
                    AddReplayControlLayer(replayFileName);
                }
            }
        }

        private static int GetCustomKeyFrameIndex(CompLayerPropertyString replayNameProperty)
        {
            CustomKeyFrame keyFrame = replayNameProperty.GetKeyAtTime(LfsRecordController.FrameIndex);
            return keyFrame == null ? -1 : keyFrame.KeyFrameIndex;
        }

        private static void UpdateReplayControlLayer(string replayFileName)
        {
            CompLayerReplayControl replayControl = (CompLayerReplayControl)LfsRecordController.project.Layers.Single(l => l is CompLayerReplayControl);
            CompLayerPropertyString replayNameProperty = (CompLayerPropertyString)replayControl.Properties[0];

            string oldReplayName = replayNameProperty.CurrentValue;
            replayNameProperty.CurrentValue = replayFileName; // Set new name.

            LfsRecordController.RecordUserAction(new UserActionKeyFrameStringValueChanged
            {
                KeyFrameIndex = GetCustomKeyFrameIndex(replayNameProperty),
                LayerIndex = replayControl.LayerIndex,
                PropertyIndex = 0,
                OldValue = oldReplayName,
                NewValue = replayFileName,
            });

            LfsRecordController.CreateUndoLevel();
        }

        private static void AddReplayControlLayer(string replayFileName)
        {
            CompLayerReplayControl replayControl = LfsRecordController.project.AddReplayControl();
            if (replayControl != null)
            {
                // Set replay filename on control.
                var replayNameProperty = ((CompLayerPropertyString)replayControl.Properties[0]);
                replayNameProperty.CurrentValue = replayFileName;

                LfsRecordController.RecordUserAction(new UserActionAddLayer()
                {
                    LayerIndex = replayControl.LayerIndex,
                    LayerName = replayControl.LayerName,
                    LayerType = replayControl.LayerType,
                });

                LfsRecordController.RecordUserAction(new UserActionKeyFrameStringValueChanged
                {
                    KeyFrameIndex = GetCustomKeyFrameIndex(replayNameProperty),
                    LayerIndex = replayControl.LayerIndex,
                    PropertyIndex = 0,
                    OldValue = String.Empty,
                    NewValue = replayFileName,
                });

                LfsRecordController.CreateUndoLevel();
            }
        }
    }
}
